<template>
  <div class="rounded border border-solid border-color-split md:flex md:flex-row md:items-stretch md:h-120">
    <div class="md:w-3/5 flex flex-col">
      <div class="pt-2 px-2 sm:pt-4 sm:px-4 border-0 border-b border-color-split border-solid">
        <!-- <div v-if="hasOrg" class="pb-2 sm:pb-4 mr-2">
          <LabelSelect
            v-model:value="orgValue"
            :is-tree-select="true"
            :label="t('aiot.organization.unit')"
            :tree-data="innerOrgData"
            :placeholder="t('aiot.organization.plzSelect')"
            :loading="orgLoading || innerOrgLoading"
            :field-names="{ label: 'companyShortName', value: 'companyId' }"
            size="small"
            class="!w-36"
          />
        </div> -->
        <div class="pb-2 sm:pb-4">
          <a-input-search
            v-model:value="keyword"
            :placeholder="t('aiot.user.search')"
            size="small"
            class="!w-full"
            :allow-clear="true"
            :maxlength="32"
            @search="keywordSearch"
          >
            <template #enterButton>
              <a-button>
                <template #icon><Icon type="icon-sousuo" /></template>
              </a-button>
            </template>
          </a-input-search>
        </div>
      </div>
      <div class="flex-1 relative rounded" :class="[showTable ? 'overflow-hidden' : 'overflow-auto']">
        <SlTable
          v-show="showTable"
          :class="{ 'ant-table-empty-noborder': tableData.length === 0 }"
          :columns="columns"
          :pagination="pagination"
          size="small"
          :data-source="tableData"
          :loading="tableLoading"
          row-key="userId"
          :row-selection="{
            selectedRowKeys: value,
            onSelect,
            getCheckboxProps,
            onSelectAll,
            hideSelectAll: singleSelect,
          }"
          :custom-row="customRow"
          :search-model="searchModel"
          :ignore-keys="['organizationId']"
        >
          <template #bodyCell="{ column, record }: BodyCellOptions<UserItem>">
            <EllipsisText v-if="column.dataIndex === 'userName'" :max-len="10" :text="record.userName" />
          </template>
        </SlTable>
        <div v-if="hasOrg" v-show="!showTable" class="py-4 px-3">
          <a-spin :spinning="loadingTree || orgLoading || memberLoading">
            <a-tree
              v-if="treeData.length > 0"
              :checked-keys="treeCheckedKeys"
              :expanded-keys="treeExpandedKeys"
              checkable
              :tree-data="treeData"
              :field-names="{ title: 'name', key: 'id' }"
              :load-data="projectId ? undefined : loadTreeData"
              :show-icon="true"
              class="user-depart-tree"
              @check="handleTreeCheck"
              @expand="treeExpand"
            >
              <template #title="{ data }">
                <span class="text-color-main">
                  {{ data.name }}
                </span>
              </template>
              <template #icon="{ data }">
                <Icon
                  class="text-xl !align-middle !leading-none !text-color-secondary"
                  :type="data.type === 'ORG' ? 'icon-organization-active' : 'icon-user-active'"
                />
              </template>
            </a-tree>
          </a-spin>
        </div>
      </div>
    </div>
    <div class="md:w-2/5 border-0 border-t md:border-t-0 md:border-l border-solid border-color-split flex flex-col">
      <div class="py-4.5 flex flex-row items-center pl-4 pr-4.5">
        <div class="flex-1">
          <span class="text-lg font-semibold text-color-header">{{ t("common.choosed") }}</span>
          <span class="text-color-secondary">({{ selectedUser.length }})</span>
        </div>
        <div class="text-red-400 cursor-pointer" @click="clearSelected">
          {{ t("common.clear") }}
        </div>
      </div>
      <div v-if="selectedUser.length > 0" class="flex-1 overflow-auto pl-4 pr-4.5">
        <div v-for="(el, i) in selectedUser" :key="el.userId" class="flex flex-row items-center mb-4">
          <div class="flex-1 overflow-hidden">
            <div>
              <span class="text-color-main">{{ el.userName }}</span>
              <span v-if="hasOrg" class="text-sm text-color-secondary">({{ el.organizations }})</span>
            </div>
            <div v-if="el.roleId && el.roleName" class="text-xs text-color-danger">
              将替换已有角色：{{ el.roleName }}
            </div>
          </div>
          <div class="cursor-pointer w-10 text-right">
            <a @click="removeSelected(el, i)">{{ t("common.remove") }}</a>
          </div>
        </div>
      </div>
      <div v-else class="flex-1 flex items-center justify-center pb-7">
        <SlEmpty />
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { useI18n } from "/@/locales/useI18n";
import { nextTick, onMounted, ref, watch } from "vue";
import type { UserItem, OrgUserSearchModel } from "/@/api/aiot/organization/models";
import { useCURD } from "/@/hooks/useCURD";
import { Api, getOrgUserByParentId, getUsers } from "/@/api/aiot/organization";
import { RequestMethodEnum } from "/@/api/req/httpEnum";
import SlEmpty from "/@/components/SlEmpty.vue";
import type { UserSelectExpose } from "/@/types/components";
import SlTable from "/@/components/SlTable.vue";
import type { OrgUserTreeItem } from "/@/api/aiot/role/models";
import type { TreeProps } from "ant-design-vue";
import EllipsisText from "/@/components/common/EllipsisText.vue";
import type { BodyCellOptions } from "/@/types/antd";
import { useUserStore } from "/@/stores/aiot/user";
import { findParents, loopItem } from "/@/utils/treeData";
import { Api as orgApi } from "/@/api/aiot/organization";
import { Api as projectSettingApi } from "/@/api/aiot/projectSetting";
import type { ProjectMemberItem } from "/@/api/aiot/projectManage/models";

const props = withDefaults(
  defineProps<{
    //所勾选的用户id数组 双向绑定
    value: string[];
    //不能选择的用户id数组
    disabledValue?: string[];
    isUserDisable?: (userItem: UserItem) => boolean;
    //外面加载过组织数据 这里就不用重复加载了
    // orgData?: OrgUserTreeItem[];
    // orgLoading?: boolean;
    //排除已授权角色用户
    excludeRoleIds?: string;
    singleSelect?: boolean;
    //指定加载项目成员和组织架构组成的数据
    projectId?: string;
    loadOnMounted?: boolean;
    handleUser?: (userItem: UserItem) => void;
  }>(),
  {
    loadOnMounted: true,
  }
);
const userStore = useUserStore();
//是否有组织架构数据 默认是, 有的话 则是树组件与table组件共存，没有的话只有table组件
const hasOrg = ref(!userStore.isPlatformUser());
const emits = defineEmits(["update:value"]);
const { t } = useI18n();
function isUserDisable(userItem: UserItem) {
  if (props.isUserDisable) {
    return props.isUserDisable(userItem);
  }
  return false;
}
/**
 * search
 */
const keyword = ref("");
if (hasOrg.value) {
  watch(keyword, (v) => {
    if (v === "") {
      showTable.value = false;
    }
  });
}
function keywordSearch() {
  if (hasOrg.value && keyword.value === "") {
    return;
  }
  showTable.value = true;
  reloadTable({
    searchText: keyword.value,
    excludeRoleIds: props.excludeRoleIds as string,
  });
}
/**
 * table
 */
const showTable = ref(hasOrg.value ? false : true);
const columns = ref([
  {
    title: t("aiot.user.name"),
    dataIndex: "userName",
  },
  {
    title: t("common.cellphone"),
    dataIndex: "loginAccount",
  },
]);
if (hasOrg.value) {
  columns.value.push({
    title: "公司(部门)",
    dataIndex: "organizations",
  });
}
const { tableData, tableLoading, pagination, reloadTable, searchModel } = useCURD<UserItem, OrgUserSearchModel>({
  getDataUrl: Api.getOrganizationUsers,
  getDataMethod: RequestMethodEnum.POST,
  loadOnMounted: false,
  loadFilter(data) {
    data.sort((a, b) => {
      return +new Date(b.createdOn as string) - +new Date(a.createdOn as string);
    });
    return data;
  },
});
if (!hasOrg.value) {
  onMounted(() => {
    reloadTable({
      searchText: "",
      excludeRoleIds: props.excludeRoleIds,
    });
  });
}
//table select
const selectedUser = ref<UserItem[]>([]);
function getCheckboxProps(record: UserItem) {
  if (props.disabledValue?.includes(record.userId as string) || isUserDisable(record)) {
    return { disabled: true };
  }
}
function onSelectAll(selected: boolean, selectedRows: UserItem[], changeRows: UserItem[]) {
  onUserSelectAll(selected, selectedRows, changeRows, false);
}
function onSelect(record: UserItem, selected: boolean) {
  onUserSelect(record, selected, false);
}
function onUserSelectAll(selected: boolean, selectedRows: UserItem[], changeRows: UserItem[], isTree?: boolean) {
  const copyValue = [...props.value];
  changeRows.forEach((record) => {
    toggleOne(selected, copyValue, record, isTree);
  });
  emits("update:value", copyValue);
}
function onUserSelect(record: UserItem, selected: boolean, isTree?: boolean) {
  const copyValue = [...props.value];
  toggleOne(selected, copyValue, record, isTree);
  emits("update:value", copyValue);
}

function toggleOne(selected: boolean, copyValue: string[], record: UserItem, isTree?: boolean) {
  props.handleUser && props.handleUser(record);
  let index = copyValue.indexOf(record.userId as string);
  let copyCheckedKeys: string[] = [...treeCheckedKeys.value];
  if (selected) {
    if (index === -1) {
      if (props.singleSelect) {
        copyValue[0] = record.userId as string;
        selectedUser.value = [record];
      } else {
        copyValue.push(record.userId as string);
        selectedUser.value.push(record);
      }
    }
    if (!isTree) {
      //同步treecheckkeys
      index = copyCheckedKeys.findIndex((key) => key === record.userId);
      if (index === -1) {
        if (props.singleSelect) {
          copyCheckedKeys = [record.userId as string];
        } else {
          copyCheckedKeys.push(record.userId as string);
        }
      }
    }
  } else {
    if (index >= 0) {
      copyValue.splice(index, 1);
      selectedUser.value.splice(index, 1);
    }
    if (!isTree) {
      //同步treecheckkeys
      index = copyCheckedKeys.findIndex((key) => key === record.userId);
      if (index >= 0) {
        copyCheckedKeys.splice(index, 1);
      }
    }
  }
  treeCheckedKeys.value = copyCheckedKeys;
}
function customRow(record: UserItem) {
  return {
    onClick() {
      if (props.disabledValue?.includes(record.userId as string) || isUserDisable(record)) {
        return;
      }
      onSelect(record, !props.value.includes(record.userId as string));
    },
  };
}
/**
 * tree
 */
const loadingTree = ref(false);
const treeCheckedKeys = ref<string[]>([]);
const treeExpandedKeys = ref<string[]>([]);
// const disabledUserObj: { [key: string]: OrgUserTreeItem } = {};
async function getTreeData(parentItem?: Partial<OrgUserTreeItem>): Promise<OrgUserTreeItem[]> {
  if (!parentItem) {
    loadingTree.value = true;
  }
  const data = await getOrgUserByParentId(parentItem ? (parentItem.companyId as string) : "0");
  loadingTree.value = false;
  if (data) {
    const result: OrgUserTreeItem[] = [];
    data.organizations.forEach((org) => {
      // if (org.memberCount > 0) {
      // }
      result.push({
        key: org.companyId,
        id: org.companyId,
        name: org.companyName,
        type: "ORG",
        isLeaf: false,
        transfterable: false,
        checkable: !props.singleSelect,
      });
    });
    //第一层的用户不加载
    data.organizationMembers.forEach((mem) => {
      // if (props.disabledValue?.includes(mem.userId)) {
      //   return;
      // }
      const disabled = props.disabledValue?.includes(mem.userId) || isUserDisable(mem);
      result.push({
        key: mem.userId,
        id: mem.userId,
        name: mem.userName,
        phone: mem.phone,
        type: "USER",
        companyShortName: parentItem ? parentItem.name : data.companyName,
        isLeaf: true,
        transfterable: true,
        disabled,
        roleId: mem.roleId,
        roleName: mem.roleName,
        isSystem: mem.isSystem,
        userId: mem.userId,
      });
    });
    if (parentItem) {
      return result;
    } else {
      return [
        {
          key: data.companyId,
          id: data.companyId,
          name: data.companyName,
          type: "ORG",
          children: result,
        },
      ];
    }
  }
  return [];
}
const loadTreeData: TreeProps["loadData"] = async (node) => {
  const data = await getTreeData({ companyId: node.id, name: node.name });
  if (node.dataRef) {
    node.dataRef.children = data as any;
    if (data.length === 0) {
      node.dataRef.isLeaf = true;
    }
  }
  //触发tree的watch事件
  treeData.value = [...treeData.value];
};
onMounted(() => {
  if (hasOrg.value && props.loadOnMounted) {
    initTreeData();
  }
});
//组织架构
const {
  tableData: orgData,
  tableLoading: orgLoading,
  reloadTable: reloadOrgData,
} = useCURD<OrgUserTreeItem>({
  getDataUrl: orgApi.getOrgTreeVoByName,
  getDataMethod: RequestMethodEnum.POST,
  loadOnMounted: false,
  onLoadSuccess(data) {
    loopItem(data, (item) => {
      item.id = item.companyId as string;
      item.name = item.companyShortName as string;
      item.type = "ORG";
      item.transfterable = false;
    });
  },
});
//项目成员数据
const {
  tableData: memberData,
  tableLoading: memberLoading,
  reloadTable: reloadMemberData,
} = useCURD<ProjectMemberItem>({
  getDataUrl: projectSettingApi.listMembersByProjectId,
  loadOnMounted: false,
});

async function initTreeData() {
  treeData.value = [];
  treeExpandedKeys.value = [];
  await nextTick();
  if (props.projectId) {
    loadingTree.value = true;
    await reloadOrgData();
    await reloadMemberData({ projectId: props.projectId });
    const notDelOrgIds: Record<string, number> = {};
    loopItem<OrgUserTreeItem>(orgData.value, (item) => {
      if (item.type === "ORG") {
        for (let i = 0; i < memberData.value.length; i++) {
          const member = memberData.value[i];
          if (member.organizationId === item.companyId) {
            const obj: OrgUserTreeItem = {
              id: member.userId as string,
              name: member.userName as string,
              type: "USER",
              key: member.userId as string,
              companyShortName: member.organizationName,
            };
            if (item.children) {
              item.children.push(obj);
            } else {
              item.children = [obj];
            }
          }
        }
      }
    });
    for (let i = 0; i < memberData.value.length; i++) {
      const member = memberData.value[i];
      const pids: string[] = [];
      findParents<OrgUserTreeItem>(orgData.value, member.userId as string, "id", pids);
      pids.forEach((id) => {
        notDelOrgIds[id] = 1;
      });
    }
    loopItem<OrgUserTreeItem>(
      orgData.value,
      (item, i, items) => {
        if (item.type === "ORG" && !notDelOrgIds[item.id]) {
          items.splice(i, 1);
        }
      },
      null,
      true
    );
    treeData.value = orgData.value;
    loadingTree.value = false;
  } else {
    treeData.value = await getTreeData();
  }
  //展开第一层
  const keys: string[] = [];
  treeData.value.forEach((el) => {
    keys.push(el.id);
  });
  treeExpandedKeys.value = keys;
}
const treeData = ref<OrgUserTreeItem[]>([]);
let orgUsersCache: { [key: string]: UserItem[] } = {};
async function getUsersByOrgId(orgId: string) {
  const key = orgId + "-" + props.excludeRoleIds;
  if (!orgUsersCache[key]) {
    const data = await getUsers({
      organizationId: orgId,
      excludeRoleIds: props.excludeRoleIds,
    });
    orgUsersCache[key] = (data as UserItem[]) || null;
  }
  return orgUsersCache[key];
}
const handleTreeCheck: TreeProps["onCheck"] = async (checkedKeys, { checkedNodes, node, checked }) => {
  if (!node.dataRef || node.dataRef.loading) return;
  if (node.type === "ORG" && !node.isLeaf) {
    let data: UserItem[];
    if (props.projectId) {
      data = [];
      loopItem<OrgUserTreeItem>((node.children || []) as OrgUserTreeItem[], (item) => {
        if (item.type === "USER" && !item.disabled) {
          data.push({
            userId: item.id,
            userName: item.name,
            organizations: item.companyShortName,
          });
        }
      });
    } else {
      //勾选节点 要调接口查询部门下所有用户数据（包括所有子孙部门下的用户）
      node.dataRef.loading = true;
      data = await getUsersByOrgId(node.id);
      data = data.filter((item) => {
        return !props.disabledValue?.includes(item.userId as string) && !isUserDisable(item);
      });
      node.dataRef.loading = false;
    }
    if (data && data.length > 0) {
      onUserSelectAll(checked, [], data, true);
    }
  }
  // console.log(checkedKeys);
  if (props.singleSelect) {
    treeCheckedKeys.value = [node.id];
  } else {
    treeCheckedKeys.value = checkedKeys as string[];
  }
  if (node.type === "USER") {
    onUserSelect(
      {
        userId: node.id,
        userName: node.name,
        organizations: node.companyShortName,
        phone: node.phone,
        roleId: node.roleId,
        roleName: node.roleName,
        isSystem: node.isSystem,
      },
      checked,
      true
    );
  }
  // selectedData.value = checkedNodes.filter((el) => el.transfterable);
};
const treeExpand: TreeProps["onExpand"] = (expandedKeys) => {
  treeExpandedKeys.value = expandedKeys as string[];
};
/**
 * tree table select
 */
watch(
  () => props.value,
  (v) => {
    if (!v || v.length === 0) {
      treeCheckedKeys.value = [];
      selectedUser.value = [];
    }
  }
);
function removeSelected(el: UserItem, i) {
  const copyValue = [...props.value];
  const j = copyValue.indexOf(el.userId as string);
  if (j >= 0) {
    copyValue.splice(j, 1);
  }
  const unCheckedKeys = [el.userId as string];
  findParents<OrgUserTreeItem>(treeData.value, el.userId as string, "id", unCheckedKeys);
  const copyCheckedKeys = [...treeCheckedKeys.value];
  for (let i = copyCheckedKeys.length - 1; i >= 0; i--) {
    if (unCheckedKeys.includes(copyCheckedKeys[i])) {
      copyCheckedKeys.splice(i, 1);
    }
  }
  treeCheckedKeys.value = copyCheckedKeys;
  selectedUser.value.splice(i, 1);
  emits("update:value", copyValue);
}
function clearSelected() {
  emits("update:value", []);
}
watch(
  () => props.disabledValue,
  (ids) => {
    if (ids) {
      if (showTable.value) {
        keywordSearch();
      }
      loopItem(
        treeData.value,
        (item, i, items) => {
          if (item.type === "USER") {
            // items.splice(i, 1);
            item.disabled = (ids.length === 0 ? false : ids.includes(item.id)) || isUserDisable(item);
          }
        },
        void 0,
        true
      );
      treeData.value = [...treeData.value];
    }
  }
);
/**
 * expose
 */
const myExpose: UserSelectExpose = {
  async reload() {
    if (showTable.value) {
      keywordSearch();
    } else {
      initTreeData();
      orgUsersCache = {};
    }
  },
  reset() {
    treeCheckedKeys.value = [];
    keyword.value = "";
    if (hasOrg.value) {
      showTable.value = false;
    } else {
      keywordSearch();
    }
    // if (orgValue.value !== "" || keyword.value !== "") {
    //   orgValue.value = "";
    //   keyword.value = "";
    //   keywordSearch();
    // }
  },
  getSelecedUser() {
    return selectedUser.value;
  },
  toggleLoading(isLoading) {
    loadingTree.value = isLoading;
  },
};
defineExpose(myExpose);
</script>
<style lang="less">
.user-depart-tree {
  .ant-tree-checkbox {
    margin: 4px 4px 0;
  }
  .ant-tree-iconEle {
    width: 18px !important;
    margin-right: 5px;
  }
}
</style>
